﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.Composition.Registration;

namespace PlutoStudio
{
    /// <summary>
    /// MEF容器定义类。
    /// </summary>
    public class MefContainer
    {
        private static MefContext _container;
        private static Func<ComposablePartCatalog, MefContext> container;
        private static ComposablePartCatalog _catalog;
        private static RegistrationBuilder _builder;
        internal static ComposablePartCatalog Catalog => _catalog;
        static MefContainer()
        {
            _builder = new RegistrationBuilder();
            container = c => _container ?? (_container = new MefContext(c));
        }

        /// <summary>
        /// 设置容器
        /// </summary>
        /// <param name="func"></param>
        public static void SetContainer(Func<ComposablePartCatalog, MefContext> func)
        {
            container = func;
        }

        /// <summary>
        /// 设置组合部件目录
        /// </summary>
        /// <param name="catalog"></param>
        public static void SetCatalog(ComposablePartCatalog catalog)
        {
            _catalog = catalog;
        }

        /// <summary>
        /// 获取容器
        /// </summary>
        public static CompositionContainer Container
        {
            get
            {
                return Context.Container;
            }
        }

        /// <summary>
        /// 获取当前容器上下文
        /// </summary>
        public static MefContext Context
        {
            get
            {
                return container(_catalog ?? (_catalog = new ApplicationCatalog(_builder))).Current;
            }
        }


        /// <summary>
        /// 获取根容器上下文
        /// </summary>
        internal static MefContext Root
        {
            get
            {
                return container(_catalog ?? (_catalog = new ApplicationCatalog(_builder)));
            }
        }


        /// <summary>
        /// 获取 RegistrationBuilder
        /// </summary>
        public static RegistrationBuilder Builder
        {
            get
            {
                return _builder;
            }
        }

        /// <summary>
        /// 设置指定类型服务的实例
        /// </summary>
        /// <typeparam name="T">服务类型</typeparam>
        /// <param name="value">服务实例</param>
        public static void SetService<T>(T value)
        {
            Container.ComposeExportedValue(value);
        }

        /// <summary>
        /// 使用指定契约名设置指定类型服务的实例
        /// </summary>
        /// <typeparam name="T">服务类型</typeparam>
        /// <param name="contractName">契约名</param>
        /// <param name="value">服务实例</param>
        public static void SetService<T>(string contractName, T value)
        {
            Container.ComposeExportedValue(contractName, value);
        }

        /// <summary>
        /// 获取指定类型服务的实例
        /// </summary>
        /// <typeparam name="T">服务类型</typeparam>
        /// <returns>服务的实例</returns>
        public static T GetService<T>()
        {
            return Container.GetExportedValueOrDefault<T>();
        }

        /// <summary>
        /// 根据契约名获取指定类型服务的实例
        /// </summary>
        /// <typeparam name="T">服务类型</typeparam>
        /// <param name="contractName">契约名</param>
        /// <returns>服务的实例</returns>
        public static T GetService<T>(string contractName)
        {
            return Container.GetExportedValueOrDefault<T>(contractName);
        }

        /// <summary>
        /// 向容器注册导出类型。
        /// </summary>
        /// <typeparam name="T">要注册的类型</typeparam>
        /// <returns></returns>
        public static PartBuilder<T> Register<T>()
        {
            return _builder.ForType<T>().Export() as PartBuilder<T>;
        }
        /// <summary>
        /// 向容器注册导出类型。
        /// </summary>
        /// <typeparam name="T">要注册的类型</typeparam>
        /// <param name="action">一个包含有关导出的配置信息的的对象。默认值为 null。</param>
        /// <returns></returns>
        public static PartBuilder<T> Register<T>(Action<ExportBuilder> action)
        {
            return _builder.ForType<T>().Export(action) as PartBuilder<T>;
        }
        /// <summary>
        /// 向容器注册导出类型。
        /// </summary>
        /// <typeparam name="T">要注册的类型</typeparam>
        /// <param name="contractName">导出类型的契约名</param>
        /// <returns></returns>
        public static PartBuilder<T> Register<T>(string contractName)
        {
            return _builder.ForType<T>().Export(s => s.AsContractName(contractName)) as PartBuilder<T>;
        }

        /// <summary>
        /// 检测指定类型是否注册。
        /// </summary>
        /// <typeparam name="T">注册的类型</typeparam>
        /// <returns>返回是否注册</returns>
        public static bool IsRegister<T>()
        {
            var exports = Container.GetExports<T>();
            return (exports?.Count() > 0);
        }

        /// <summary>
        /// 向容器注册导出类型的接口。
        /// </summary>
        /// <returns></returns>
        public static PartBuilder RegisterInterface(Type classType)
        {
            return _builder.ForType(classType).ExportInterfaces().Export();
        }


        /// <summary>
        /// 向容器注册指定接口的导出类型。
        /// </summary>
        /// <typeparam name="TClass">要导出的类型</typeparam>
        /// <typeparam name="TInterface">协定的类型</typeparam>
        /// <returns></returns>
        public static PartBuilder<TClass> Register<TClass, TInterface>() where TClass : TInterface
        {
            return _builder.ForType<TClass>().Export<TInterface>() as PartBuilder<TClass>;
        }
        /// <summary>
        /// 向容器注册指定接口的导出类型。
        /// </summary>
        /// <typeparam name="TClass">要导出的类型</typeparam>
        /// <typeparam name="TInterface">协定的类型</typeparam>
        /// <param name="action">一个包含有关导出的配置信息的的对象。默认值为 null。</param>
        /// <returns></returns>
        public static PartBuilder<TClass> Register<TClass, TInterface>(Action<ExportBuilder> action) where TClass : TInterface
        {
            return _builder.ForType<TClass>().Export<TInterface>(action) as PartBuilder<TClass>;
        }
        /// <summary>
        /// 向容器注册指定接口的导出类型。
        /// </summary>
        /// <typeparam name="TClass">要导出的类型</typeparam>
        /// <typeparam name="TInterface">协定的类型</typeparam>
        /// <param name="contractName">导出类型的契约名</param>
        /// <returns></returns>
        public static PartBuilder<TClass> Register<TClass, TInterface>(string contractName) where TClass : TInterface
        {
            return _builder.ForType<TClass>().Export<TInterface>(s => s.AsContractName(contractName)) as PartBuilder<TClass>;
        }
    }

    public class MefContext : IDisposable
    {
        private CompositionContainer _container;


        internal CompositionContainer Container => _container;

        private MefContext _parent;

        private MefContext _next;

        /// <summary>
        /// 
        /// </summary>
        public MefContext()
        {
            MefContainer.Context._next = this;
            _container = new CompositionContainer(MefContainer.Catalog);
        }

        internal MefContext Current
        {
            get
            {
                var current = MefContainer.Root;
                while (current._next != null)
                {
                    current = current._next;
                }
                return current;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="catalog"></param>
        public MefContext(ComposablePartCatalog catalog)
        {
            _container = new CompositionContainer(catalog);

        }

        /// <summary>
        /// 设置指定类型服务的实例
        /// </summary>
        /// <typeparam name="T">服务类型</typeparam>
        /// <param name="value">服务实例</param>
        public void SetService<T>(T value)
        {
            _container.ComposeExportedValue(value);
        }

        /// <summary>
        /// 使用指定契约名设置指定类型服务的实例
        /// </summary>
        /// <typeparam name="T">服务类型</typeparam>
        /// <param name="contractName">契约名</param>
        /// <param name="value">服务实例</param>
        public void SetService<T>(string contractName, T value)
        {
            _container.ComposeExportedValue(contractName, value);
        }

        /// <summary>
        /// 获取指定类型服务的实例
        /// </summary>
        /// <typeparam name="T">服务类型</typeparam>
        /// <returns>服务的实例</returns>
        public T GetService<T>()
        {
            return _container.GetExportedValueOrDefault<T>();
        }

        /// <summary>
        /// 根据契约名获取指定类型服务的实例
        /// </summary>
        /// <typeparam name="T">服务类型</typeparam>
        /// <param name="contractName">契约名</param>
        /// <returns>服务的实例</returns>
        public T GetService<T>(string contractName)
        {
            return _container.GetExportedValueOrDefault<T>(contractName);
        }


        void IDisposable.Dispose()
        {
            _container.Dispose();
            if (_parent != null)
            {
                _parent._next = null;
                _parent = null;
            }
            var context = this;
            while (context._next != null)
            {
                context = _next;
                context._container.Dispose();
            }
        }
    }

}
